home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 52 / Amiga Format AFCD52 (Issue 136, May 2000).iso / -screenplay- / shareware / warpquake / warpquakesrc / console.c < prev    next >
C/C++ Source or Header  |  2000-02-29  |  13KB  |  650 lines

  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. // console.c
  21.  
  22. #ifdef NeXT
  23. #include <libc.h>
  24. #endif
  25. #ifndef _MSC_VER
  26. #include <unistd.h>
  27. #endif
  28. #include <fcntl.h>
  29. #include "quakedef.h"
  30.  
  31. int         con_linewidth;
  32.  
  33. float        con_cursorspeed = 4;
  34.  
  35. #define        CON_TEXTSIZE    16384
  36.  
  37. qboolean     con_forcedup;        // because no entities to refresh
  38.  
  39. int            con_totallines;        // total lines in console scrollback
  40. int            con_backscroll;        // lines up from bottom to display
  41. int            con_current;        // where next message will be printed
  42. int            con_x;                // offset in current line for next print
  43. char        *con_text=0;
  44.  
  45. cvar_t        con_notifytime = {"con_notifytime","3"};        //seconds
  46.  
  47. #define    NUM_CON_TIMES 4
  48. float        con_times[NUM_CON_TIMES];    // realtime time the line was generated
  49.                                 // for transparent notify lines
  50.  
  51. int            con_vislines;
  52.  
  53. qboolean    con_debuglog;
  54.  
  55. #define        MAXCMDLINE    256
  56. extern    char    key_lines[32][MAXCMDLINE];
  57. extern    int        edit_line;
  58. extern    int        key_linepos;
  59.         
  60.  
  61. qboolean    con_initialized;
  62.  
  63. int            con_notifylines;        // scan lines to clear for notify lines
  64.  
  65. extern void M_Menu_Main_f (void);
  66.  
  67. /*
  68. ================
  69. Con_ToggleConsole_f
  70. ================
  71. */
  72. void Con_ToggleConsole_f (void)
  73. {
  74.     if (key_dest == key_console)
  75.     {
  76.         if (cls.state == ca_connected)
  77.         {
  78.             key_dest = key_game;
  79.             key_lines[edit_line][1] = 0;    // clear any typing
  80.             key_linepos = 1;
  81.         }
  82.         else
  83.         {
  84.             M_Menu_Main_f ();
  85.         }
  86.     }
  87.     else
  88.         key_dest = key_console;
  89.     
  90.     SCR_EndLoadingPlaque ();
  91.     memset (con_times, 0, sizeof(con_times));
  92. }
  93.  
  94. /*
  95. ================
  96. Con_Clear_f
  97. ================
  98. */
  99. void Con_Clear_f (void)
  100. {
  101.     if (con_text)
  102.         Q_memset (con_text, ' ', CON_TEXTSIZE);
  103. }
  104.  
  105.                         
  106. /*
  107. ================
  108. Con_ClearNotify
  109. ================
  110. */
  111. void Con_ClearNotify (void)
  112. {
  113.     int        i;
  114.     
  115.     for (i=0 ; i<NUM_CON_TIMES ; i++)
  116.         con_times[i] = 0;
  117. }
  118.  
  119.                         
  120. /*
  121. ================
  122. Con_MessageMode_f
  123. ================
  124. */
  125. extern qboolean team_message;
  126.  
  127. void Con_MessageMode_f (void)
  128. {
  129.     key_dest = key_message;
  130.     team_message = false;
  131. }
  132.  
  133.                         
  134. /*
  135. ================
  136. Con_MessageMode2_f
  137. ================
  138. */
  139. void Con_MessageMode2_f (void)
  140. {
  141.     key_dest = key_message;
  142.     team_message = true;
  143. }
  144.  
  145.                         
  146. /*
  147. ================
  148. Con_CheckResize
  149.  
  150. If the line width has changed, reformat the buffer.
  151. ================
  152. */
  153. void Con_CheckResize (void)
  154. {
  155.     int        i, j, width, oldwidth, oldtotallines, numlines, numchars;
  156.     char    tbuf[CON_TEXTSIZE];
  157.  
  158.     width = (vid.width >> 3) - 2;
  159.  
  160.     if (width == con_linewidth)
  161.         return;
  162.  
  163.     if (width < 1)            // video hasn't been initialized yet
  164.     {
  165.         width = 38;
  166.         con_linewidth = width;
  167.         con_totallines = CON_TEXTSIZE / con_linewidth;
  168.         Q_memset (con_text, ' ', CON_TEXTSIZE);
  169.     }
  170.     else
  171.     {
  172.         oldwidth = con_linewidth;
  173.         con_linewidth = width;
  174.         oldtotallines = con_totallines;
  175.         con_totallines = CON_TEXTSIZE / con_linewidth;
  176.         numlines = oldtotallines;
  177.  
  178.         if (con_totallines < numlines)
  179.             numlines = con_totallines;
  180.  
  181.         numchars = oldwidth;
  182.     
  183.         if (con_linewidth < numchars)
  184.             numchars = con_linewidth;
  185.  
  186.         Q_memcpy (tbuf, con_text, CON_TEXTSIZE);
  187.         Q_memset (con_text, ' ', CON_TEXTSIZE);
  188.  
  189.         for (i=0 ; i<numlines ; i++)
  190.         {
  191.             for (j=0 ; j<numchars ; j++)
  192.             {
  193.                 con_text[(con_totallines - 1 - i) * con_linewidth + j] =
  194.                         tbuf[((con_current - i + oldtotallines) %
  195.                               oldtotallines) * oldwidth + j];
  196.             }
  197.         }
  198.  
  199.         Con_ClearNotify ();
  200.     }
  201.  
  202.     con_backscroll = 0;
  203.     con_current = con_totallines - 1;
  204. }
  205.  
  206.  
  207. /*
  208. ================
  209. Con_Init
  210. ================
  211. */
  212. void Con_Init (void)
  213. {
  214. #define MAXGAMEDIRLEN    1000
  215.     char    temp[MAXGAMEDIRLEN+1];
  216.     char    *t2 = "/qconsole.log";
  217.  
  218.     con_debuglog = COM_CheckParm("-condebug");
  219.  
  220.     if (con_debuglog)
  221.     {
  222.         if (strlen (com_gamedir) < (MAXGAMEDIRLEN - strlen (t2)))
  223.         {
  224.             sprintf (temp, "%s%s", com_gamedir, t2);
  225.             unlink (temp);
  226.         }
  227.     }
  228.  
  229.     con_text = Hunk_AllocName (CON_TEXTSIZE, "context");
  230.     Q_memset (con_text, ' ', CON_TEXTSIZE);
  231.     con_linewidth = -1;
  232.     Con_CheckResize ();
  233.     
  234.     Con_Printf ("Console initialized.\n");
  235.  
  236. //
  237. // register our commands
  238. //
  239.     Cvar_RegisterVariable (&con_notifytime);
  240.  
  241.     Cmd_AddCommand ("toggleconsole", Con_ToggleConsole_f);
  242.     Cmd_AddCommand ("messagemode", Con_MessageMode_f);
  243.     Cmd_AddCommand ("messagemode2", Con_MessageMode2_f);
  244.     Cmd_AddCommand ("clear", Con_Clear_f);
  245.     con_initialized = true;
  246. }
  247.  
  248.  
  249. /*
  250. ===============
  251. Con_Linefeed
  252. ===============
  253. */
  254. void Con_Linefeed (void)
  255. {
  256.     con_x = 0;
  257.     con_current++;
  258.     Q_memset (&con_text[(con_current%con_totallines)*con_linewidth]
  259.     , ' ', con_linewidth);
  260. }
  261.  
  262. /*
  263. ================
  264. Con_Print
  265.  
  266. Handles cursor positioning, line wrapping, etc
  267. All console printing must go through this in order to be logged to disk
  268. If no console is visible, the notify window will pop up.
  269. ================
  270. */
  271. void Con_Print (char *txt)
  272. {
  273.     int        y;
  274.     int        c, l;
  275.     static int    cr;
  276.     int        mask;
  277.     
  278.     con_backscroll = 0;
  279.  
  280.     if (txt[0] == 1)
  281.     {
  282.         mask = 128;        // go to colored text
  283.         S_LocalSound ("misc/talk.wav");
  284.     // play talk wav
  285.         txt++;
  286.     }
  287.     else if (txt[0] == 2)
  288.     {
  289.         mask = 128;        // go to colored text
  290.         txt++;
  291.     }
  292.     else
  293.         mask = 0;
  294.  
  295.  
  296.     while ( (c = *txt) )
  297.     {
  298.     // count word length
  299.         for (l=0 ; l< con_linewidth ; l++)
  300.             if ( txt[l] <= ' ')
  301.                 break;
  302.  
  303.     // word wrap
  304.         if (l != con_linewidth && (con_x + l > con_linewidth) )
  305.             con_x = 0;
  306.  
  307.         txt++;
  308.  
  309.         if (cr)
  310.         {
  311.             con_current--;
  312.             cr = false;
  313.         }
  314.  
  315.         
  316.         if (!con_x)
  317.         {
  318.             Con_Linefeed ();
  319.         // mark time for transparent overlay
  320.             if (con_current >= 0)
  321.                 con_times[con_current % NUM_CON_TIMES] = realtime;
  322.         }
  323.  
  324.         switch (c)
  325.         {
  326.         case '\n':
  327.             con_x = 0;
  328.             break;
  329.  
  330.         case '\r':
  331.             con_x = 0;
  332.             cr = 1;
  333.             break;
  334.  
  335.         default:    // display character and advance
  336.             y = con_current % con_totallines;
  337.             con_text[y*con_linewidth+con_x] = c | mask;
  338.             con_x++;
  339.             if (con_x >= con_linewidth)
  340.                 con_x = 0;
  341.             break;
  342.         }
  343.         
  344.     }
  345. }
  346.  
  347.  
  348. /*
  349. ================
  350. Con_DebugLog
  351. ================
  352. */
  353. void Con_DebugLog(char *file, char *fmt, ...)
  354. {
  355.     va_list argptr; 
  356.     static char data[1024];
  357.     int fd;
  358.     
  359.     va_start(argptr, fmt);
  360.     vsprintf(data, fmt, argptr);
  361.     va_end(argptr);
  362.     fd = open(file, O_WRONLY | O_CREAT | O_APPEND, 0666);
  363.     write(fd, data, strlen(data));
  364.     close(fd);
  365. }
  366.  
  367.  
  368. /*
  369. ================
  370. Con_Printf
  371.  
  372. Handles cursor positioning, line wrapping, etc
  373. ================
  374. */
  375. #define    MAXPRINTMSG    4096
  376. // FIXME: make a buffer size safe vsprintf?
  377. void Con_Printf (char *fmt, ...)
  378. {
  379.     va_list        argptr;
  380.     char        msg[MAXPRINTMSG];
  381.     static qboolean    inupdate;
  382.     
  383.     va_start (argptr,fmt);
  384.     vsprintf (msg,fmt,argptr);
  385.     va_end (argptr);
  386.     
  387. // also echo to debugging console
  388.     Sys_Printf ("%s", msg);    // also echo to debugging console
  389.  
  390. // log all messages to file
  391.     if (con_debuglog)
  392.         Con_DebugLog(va("%s/qconsole.log",com_gamedir), "%s", msg);
  393.  
  394.     if (!con_initialized)
  395.         return;
  396.         
  397.     if (cls.state == ca_dedicated)
  398.         return;        // no graphics mode
  399.  
  400. // write it to the scrollable buffer
  401.     Con_Print (msg);
  402.     
  403. // update the screen if the console is displayed
  404.     if (cls.signon != SIGNONS && !scr_disabled_for_loading )
  405.     {
  406.     // protect against infinite loop if something in SCR_UpdateScreen calls
  407.     // Con_Printd
  408.         if (!inupdate)
  409.         {
  410.             inupdate = true;
  411.             SCR_UpdateScreen ();
  412.             inupdate = false;
  413.         }
  414.     }
  415. }
  416.  
  417. /*
  418. ================
  419. Con_DPrintf
  420.  
  421. A Con_Printf that only shows up if the "developer" cvar is set
  422. ================
  423. */
  424. void Con_DPrintf (char *fmt, ...)
  425. {
  426.     va_list        argptr;
  427.     char        msg[MAXPRINTMSG];
  428.         
  429.     if (!developer.value)
  430.         return;            // don't confuse non-developers with techie stuff...
  431.  
  432.     va_start (argptr,fmt);
  433.     vsprintf (msg,fmt,argptr);
  434.     va_end (argptr);
  435.     
  436.     Con_Printf ("%s", msg);
  437. }
  438.  
  439.  
  440. /*
  441. ==================
  442. Con_SafePrintf
  443.  
  444. Okay to call even when the screen can't be updated
  445. ==================
  446. */
  447. void Con_SafePrintf (char *fmt, ...)
  448. {
  449.     va_list        argptr;
  450.     char        msg[1024];
  451.     int            temp;
  452.         
  453.     va_start (argptr,fmt);
  454.     vsprintf (msg,fmt,argptr);
  455.     va_end (argptr);
  456.  
  457.     temp = scr_disabled_for_loading;
  458.     scr_disabled_for_loading = true;
  459.     Con_Printf ("%s", msg);
  460.     scr_disabled_for_loading = temp;
  461. }
  462.  
  463.  
  464. /*
  465. ==============================================================================
  466.  
  467. DRAWING
  468.  
  469. ==============================================================================
  470. */
  471.  
  472.  
  473. /*
  474. ================
  475. Con_DrawInput
  476.  
  477. The input line scrolls horizontally if typing goes beyond the right edge
  478. ================
  479. */
  480. void Con_DrawInput (void)
  481. {
  482.     int        y;
  483.     int        i;
  484.     char    *text;
  485.  
  486.     if (key_dest != key_console && !con_forcedup)
  487.         return;        // don't draw anything
  488.  
  489.     text = key_lines[edit_line];
  490.     
  491. // add the cursor frame
  492.     text[key_linepos] = 10+((int)(realtime*con_cursorspeed)&1);
  493.     
  494. // fill out remainder with spaces
  495.     for (i=key_linepos+1 ; i< con_linewidth ; i++)
  496.         text[i] = ' ';
  497.         
  498. //    prestep if horizontally scrolling
  499.     if (key_linepos >= con_linewidth)
  500.         text += 1 + key_linepos - con_linewidth;
  501.         
  502. // draw it
  503.     y = con_vislines-16;
  504.  
  505.     for (i=0 ; i<con_linewidth ; i++)
  506.         Draw_Character ( (i+1)<<3, con_vislines - 16, text[i]);
  507.  
  508. // remove cursor
  509.     key_lines[edit_line][key_linepos] = 0;
  510. }
  511.  
  512.  
  513. /*
  514. ================
  515. Con_DrawNotify
  516.  
  517. Draws the last few lines of output transparently over the game top
  518. ================
  519. */
  520. void Con_DrawNotify (void)
  521. {
  522.     int        x, v;
  523.     char    *text;
  524.     int        i;
  525.     float    time;
  526.     extern char chat_buffer[];
  527.  
  528.     v = 0;
  529.     for (i= con_current-NUM_CON_TIMES+1 ; i<=con_current ; i++)
  530.     {
  531.         if (i < 0)
  532.             continue;
  533.         time = con_times[i % NUM_CON_TIMES];
  534.         if (time == 0)
  535.             continue;
  536.         time = realtime - time;
  537.         if (time > con_notifytime.value)
  538.             continue;
  539.         text = con_text + (i % con_totallines)*con_linewidth;
  540.         
  541.         clearnotify = 0;
  542.         scr_copytop = 1;
  543.  
  544.         for (x = 0 ; x < con_linewidth ; x++)
  545.             Draw_Character ( (x+1)<<3, v, text[x]);
  546.  
  547.         v += 8;
  548.     }
  549.  
  550.  
  551.     if (key_dest == key_message)
  552.     {
  553.         clearnotify = 0;
  554.         scr_copytop = 1;
  555.     
  556.         x = 0;
  557.         
  558.         Draw_String (8, v, "say:");
  559.         while(chat_buffer[x])
  560.         {
  561.             Draw_Character ( (x+5)<<3, v, chat_buffer[x]);
  562.             x++;
  563.         }
  564.         Draw_Character ( (x+5)<<3, v, 10+((int)(realtime*con_cursorspeed)&1));
  565.         v += 8;
  566.     }
  567.     
  568.     if (v > con_notifylines)
  569.         con_notifylines = v;
  570. }
  571.  
  572. /*
  573. ================
  574. Con_DrawConsole
  575.  
  576. Draws the console with the solid background
  577. The typing input line at the bottom should only be drawn if typing is allowed
  578. ================
  579. */
  580. void Con_DrawConsole (int lines, qboolean drawinput)
  581. {
  582.     int                i, x, y;
  583.     int                rows;
  584.     char            *text;
  585.     int                j;
  586.     
  587.     if (lines <= 0)
  588.         return;
  589.  
  590. // draw the background
  591.     Draw_ConsoleBackground (lines);
  592.  
  593. // draw the text
  594.     con_vislines = lines;
  595.  
  596.     rows = (lines-16)>>3;        // rows of text to draw
  597.     y = lines - 16 - (rows<<3);    // may start slightly negative
  598.  
  599.     for (i= con_current - rows + 1 ; i<=con_current ; i++, y+=8 )
  600.     {
  601.         j = i - con_backscroll;
  602.         if (j<0)
  603.             j = 0;
  604.         text = con_text + (j % con_totallines)*con_linewidth;
  605.  
  606.         for (x=0 ; x<con_linewidth ; x++)
  607.             Draw_Character ( (x+1)<<3, y, text[x]);
  608.     }
  609.  
  610. // draw the input prompt, user text, and cursor if desired
  611.     if (drawinput)
  612.         Con_DrawInput ();
  613. }
  614.  
  615.  
  616. /*
  617. ==================
  618. Con_NotifyBox
  619. ==================
  620. */
  621. void Con_NotifyBox (char *text)
  622. {
  623.     double        t1, t2;
  624.  
  625. // during startup for sound / cd warnings
  626.     Con_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n");
  627.  
  628.     Con_Printf (text);
  629.  
  630.     Con_Printf ("Press a key.\n");
  631.     Con_Printf("\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n");
  632.  
  633.     key_count = -2;        // wait for a key down and up
  634.     key_dest = key_console;
  635.  
  636.     do
  637.     {
  638.         t1 = Sys_FloatTime ();
  639.         SCR_UpdateScreen ();
  640.         Sys_SendKeyEvents ();
  641.         t2 = Sys_FloatTime ();
  642.         realtime += t2-t1;        // make the cursor blink
  643.     } while (key_count < 0);
  644.  
  645.     Con_Printf ("\n");
  646.     key_dest = key_game;
  647.     realtime = 0;                // put the cursor back to invisible
  648. }
  649.  
  650.